﻿/**************************************************************************************
*
* Filename: IMetaDataDocument.cs
* Description: 
* Author: Fengyuan Zhang (Franklin Zhang) 
* Company: Nanjing Normal University OpenGMS
* Date: 2018/9/20
*
**************************************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;

namespace nxmodel.mdl.csharp
{
    //! Model Mechanism Item
    public struct MechanismItem
    {
        public string Name;
        public string Value;

        public MechanismItem(string name, string value)
        {
            this.Name = name;
            this.Value = value;
        }

        public static bool operator ==(MechanismItem itemA, MechanismItem itemB)
        {
            if (itemA.Name == itemB.Name && itemA.Value == itemB.Value)
            {
                return true;
            }
            return false;
        }

        public static bool operator !=(MechanismItem itemA, MechanismItem itemB)
        {
            return !(itemA == itemB);
        }
    };

    //! Model method type
    public enum EMethodType
    {
        EMMT_Unknown = 0,
        EMMT_Algorithm = 1,
        EMMT_Formula = 2
    };

    //! Model method
    public struct MethodItem
    {
        public string Name;
        public EMethodType Type;
        public string Value;

        public MethodItem(string name, EMethodType type, string value)
        {
            this.Name = name;
            this.Type = type;
            this.Value = value;
        }

        public static bool operator == (MethodItem itemA, MethodItem itemB)
        {
            if (itemA.Name == itemB.Name && itemA.Type == itemB.Type && itemA.Value == itemB.Value)
            {
                return true;
            }
            return false;
        }

        public static bool operator !=(MethodItem itemA, MethodItem itemB)
        {
            return !(itemA == itemB);
        }
    };

    //! Scale type
    public enum ESpatialScale
    {
        ESS_Unknown = 0,
        ESS_Global = 1,
        ESS_Large = 2,
        ESS_Middle = 3,
        ESS_Small = 4
    };

    //! Spatail reference type
    public enum ESpatialReferenceType
    {
        ESRT_Unknown = 0,
        ESRT_Projected = 1,
        ESRT_Geographic = 2,
        ESRT_All = 3,
        ESRT_Specific = 4
    };

    //! Spatial or temporal resolution
    public struct SpatialTemporalStepItem
    {
        public string Key;
        public string Value;
        public string Unit;

        public SpatialTemporalStepItem(string key, string value, string unit)
        {
            this.Key = key;
            this.Value = value;
            this.Unit = unit;
        }

        public static bool operator == (SpatialTemporalStepItem itemA, SpatialTemporalStepItem itemB)
        {
            if (itemA.Key == itemB.Key && itemA.Value == itemB.Value && itemA.Unit == itemB.Unit)
            {
                return true;
            }
            return false;
        }

        public static bool operator !=(SpatialTemporalStepItem itemA, SpatialTemporalStepItem itemB)
        {
            return !(itemA == itemB);
        }
    };
    
    //! Extent type
    public enum EExtentType
    {
        EET_Unknown = 0,
        EET_Envelope = 1,
        EET_Polygon = 2,
        EET_Text = 3
    };

    //! Spatial Extent
    public struct SpatialExtentItem
    {
        public string Name;
        public EExtentType Type;
        public string Value;
        public string SReference;

        public SpatialExtentItem(string name, EExtentType type, string value, string sReference)
        {
            this.Name = name;
            this.Type = type;
            this.Value = value;
            this.SReference = sReference;
        }

        public static bool operator ==(SpatialExtentItem itemA, SpatialExtentItem itemB)
        {
            if (itemA.Name == itemB.Name && itemA.Type == itemB.Type && itemA.Value == itemB.Value && itemA.SReference == itemB.SReference)
            {
                return true;
            }
            return false;
        }

        public static bool operator !=(SpatialExtentItem itemA, SpatialExtentItem itemB)
        {
            return !(itemA == itemB);
        }
    };

    //! Temporal scale
    public enum ETemporalScale
    {
        ETS_Unknown = 0,
        ETS_All = 1,
        ETS_Large = 2,
        ETS_Middle = 3,
        ETS_Small = 4
    };

    //! Temporal reference type
    public enum ETimeReferenceType
    {
        ETRT_Unknown = 0,
        ETRT_UNIX = 1
    };

    //! Time extent item type
    public enum ETimeExtentItemType
    {
        ETEIT_Unknown = 0,
        ETEIT_Span = 1
    };

    //! Time extent item
    public struct TimeExtentItem
    {
        public string Name;
        public ETimeExtentItemType Type;
        public string Value;
        public string Unit;

        public TimeExtentItem(string name, ETimeExtentItemType type, string value, string unit)
        {
            this.Name = name;
            this.Type = type;
            this.Value = value;
            this.Unit = unit;
        }

        public static bool operator ==(TimeExtentItem itemA, TimeExtentItem itemB)
        {
            if (itemA.Name == itemB.Name && itemA.Type == itemB.Type && itemA.Value == itemB.Value && itemA.Unit == itemB.Unit)
            {
                return true;
            }
            return false;
        }

        public static bool operator !=(TimeExtentItem itemA, TimeExtentItem itemB)
        {
            return !(itemA == itemB);
        }
    };

    //! Contributor institution
    public struct ContributorInstitution
    {
        public string Name;
        public string Country;
        public string City;
        public string Address;

        public ContributorInstitution(string name, string country, string city, string address)
        {
            this.Name = name;
            this.Country = country;
            this.City = city;
            this.Address = address;
        }

        public static bool operator == (ContributorInstitution itemA, ContributorInstitution itemB)
        {
            if (itemA.Name == itemB.Name && itemA.Country == itemB.Country && itemA.City == itemB.City && itemA.Address == itemB.Address)
            {
                return true;
            }
            return false;
        }

        public static bool operator !=(ContributorInstitution itemA, ContributorInstitution itemB)
        {
            return !(itemA == itemB);
        }
    };

    //! Contributor role type
    public enum EContributorRoleType
    {
        ECRT_Other = 0,
        ECRT_Author = 1,
        ECRT_Developer = 2,
        ECRT_Wrapper = 3
    };

    //! Contributor role item
    public struct ContributorRoleItem
    {
        public EContributorRoleType Role;
        public string Description;

        public ContributorRoleItem(EContributorRoleType role, string description)
        {
            this.Role = role;
            this.Description = description;
        }

        public static bool operator ==(ContributorRoleItem itemA, ContributorRoleItem itemB)
        {
            if (itemA.Role == itemB.Role && itemA.Description == itemB.Description)
            {
                return true;
            }
            return false;
        }

        public static bool operator !=(ContributorRoleItem itemA, ContributorRoleItem itemB)
        {
            return !(itemA == itemB);
        }
    };

    //! Contributor contact type
    public enum EContributorContactType
    {
        ECCT_Other = 0,
        ECCT_Email = 1,
        ECCT_Fax = 2,
        ECCT_Phone = 3,
        ECCT_URL = 4 
    };

    //! Contributor contact
    public struct ContributorContactItem
    {
        public EContributorContactType Type;
        public string Value;

        public ContributorContactItem(EContributorContactType type, string value)
        {
            this.Type = type;
            this.Value = value;
        }

        public static bool operator ==(ContributorContactItem itemA, ContributorContactItem itemB)
        {
            if (itemA.Type == itemB.Type && itemA.Value == itemB.Value)
            {
                return true;
            }
            return false;
        }

        public static bool operator !=(ContributorContactItem itemA, ContributorContactItem itemB)
        {
            return !(itemA == itemB);
        }
    };

    //! Contributor interface
    public interface IContributor
    {
        //! Name
        string Name { get; set; }

        //! Account
        string Account { get; set; }

        //! Institution
        ContributorInstitution Institution { get; set; }

        //! get contributor role
        ContributorRoleItem getRole(int index);

        //! get contributor count
        int RolesCount { get; }

        //! add a role
        int insertRole(ContributorRoleItem role);

        //! remove a role
        int removeRole(int index);

        //! get contact
        ContributorContactItem getContact(int index);

        //! get contacts count
        int ContactsCount { get; }

        //! add a contact
        int insertContact(ContributorContactItem item);

        //! remvoe a contact
        int removeContact(int index);

        //! format to xml
        bool formatToXml(ref XmlElement contributorsEle);

        //! load xml
        bool loadXml(XmlElement contributorEle);
    };

    //! Component
    public struct ComponentItem
    {
        public string Name;
        public string Description;
        public string URL;

        public ComponentItem(string name, string description, string url)
        {
            this.Name = name;
            this.Description = description;
            this.URL = url;
        }

        public static bool operator == (ComponentItem itemA, ComponentItem itemB)
        {
            if (itemA.Name == itemB.Name && itemA.Description == itemB.Description && itemA.URL == itemB.URL)
            {
                return true;
            }
            return false;
        }


        public static bool operator !=(ComponentItem itemA, ComponentItem itemB)
        {
            return !(itemA == itemB);
        }
    };

    //! Processing type
    public enum EProcessingType
    {
        ERP_Other = 0,
        EPT_Preprocessing = 1,
        EPT_Postprocessing = 2,
        EPT_Visualization = 3,
    };

    //! Processing item
    public struct ProcessingItem
    {
        public string Name;
        public EProcessingType Type;
        public string Description;
        public string URL;

        public ProcessingItem(string name, EProcessingType type, string description, string url)
        {
            this.Name = name;
            this.Type = type;
            this.Description = description;
            this.URL = url;
        }

        public static bool operator ==(ProcessingItem itemA, ProcessingItem itemB)
        {
            if (itemA.Name == itemB.Name && itemA.Type == itemB.Type && itemA.Description == itemB.Description && itemA.URL == itemB.URL)
            {
                return true;
            }
            return false;
        }

        public static bool operator !=(ProcessingItem itemA, ProcessingItem itemB)
        {
            return !(itemA == itemB);
        }
    };

    //! Programming languages
    public enum EProgrammingLanguage
    {
        EPL_Other = 0,
        EPL_C = 1,
        EPL_CPP = 2,
        EPL_CSharp = 3,
        EPL_Python = 4,
        EPL_Fortran = 5,
        EPL_Java = 6,
        EPL_Javascript = 7,
        EPL_R = 8,
        EPL_Basic = 9,
        EPL_Lua = 10,
        EPL_Matlab = 11,
        EPL_Shell = 12
    };

    //! Potential coupling component
    public struct PotentialCouplingComponent
    {
        public string Name;
        public string Description;
        public string URL;
        public List<string> List_Methods;

        public PotentialCouplingComponent(string name, string description, string url, List<string> list_methods)
        {
            this.Name = name;
            this.Description = description;
            this.URL = url;
            this.List_Methods = list_methods;
        }

        public static bool operator ==(PotentialCouplingComponent itemA, PotentialCouplingComponent itemB)
        {
            if (itemA.Name != itemB.Name)
            {
                return false;
            }
            if (itemA.Description != itemB.Description)
            {
                return false;
            }
            if (itemA.URL != itemB.URL)
            {
                return false;
            }
            if (itemA.List_Methods.Count != itemB.List_Methods.Count)
            {
                return false;
            }
            for (int i = 0; i < itemA.List_Methods.Count; i++)
            {
                if (!itemB.List_Methods.Contains(itemA.List_Methods[i]))
                {
                    return false;
                }
            }
            return true;
        }


        public static bool operator !=(PotentialCouplingComponent itemA, PotentialCouplingComponent itemB)
        {
            return !(itemA == itemB);
        }
    };

    //! Spatiotemporal interface
    public interface ISpatiotemporalInfo
    {
        /* Spatial Information */
        //! is any spatial information
        bool SpatailInfoEnabled { get; set; }

        //! Spatial Dimension
        //! get spatial dimensions
        string getSpatialDimension(int index);

        //! get dimensions count
        int SpatialDimensionsCount { get; }

        //! add a dimension
        int insertDimension(string dimesion);

        //! remove a dimension
        int removeDimension(int index);

        //! Scale
        //! scale type
        ESpatialScale SpatialScaleType { get; set; }

        //! scale description
        string SpatialScaleDescription { get; set; }

        //! Spatial Reference
        //! spatial reference type
        ESpatialReferenceType SpatialReferenceType { get; set; }

        //! spatial reference WKT
        string SpatialReferenceWKT { get; set; }

        //! Spatial Resolution Constraint
        //! get resolution constraint
        SpatialTemporalStepItem getSpatialResolutionItem(int index);

        //! get resolution constraint count
        int SpatialResolutionItemCount { get; }

        //! add resolution constraint
        int insertSpatialResolutionItem(SpatialTemporalStepItem item);

        //! remove resolution constraint
        int removeSpatialResolutionItem(int index);

        //! Spatial Extents
        //! get spatial extent
        SpatialExtentItem getSpatialExtent(int index);

        //! get spatial extents count
        int SpatialExtentsCount { get; }

        //! add a spatial extent
        int insertSpatialExtent(SpatialExtentItem extent);

        //! remove a spatial extent
        int removeSpatialExtent(int index);

        /* Temproal Information */
        //! is any temproal information
        bool TemproalInfoEnabled { get; set; }

        //! Time Scale
        //! get scale type
        ETemporalScale TimeScaleType { get; set; }

        //! get scale description
        string TimeScaleDescription { get; set; }

        //! Time Reference
        //! time reference type
        ETimeReferenceType TimeReferenceType { get; set; }

        //! time reference value
        string TimeReferenceValue { get; set; }

        //! Time Step Constraint
        //! get resolution constraint
        SpatialTemporalStepItem getTimeStepItem(int index);

        //! get resolution constraint count
        int TimeStepItemCount { get; }

        //! add resolution constraint
        int insertTimeStepItem(SpatialTemporalStepItem item);

        //! remove resolution constraint
        int removeTimeStepItem(int index);

        //! Time Extents
        //! get time extent
        TimeExtentItem getTimeExtent(int index);

        //! get time extents count
        int TimeExtentsCount { get; }

        //! add a time extent
        int insertTimeExtent(TimeExtentItem item);

        //! remove a time extent
        int removeTimeExtent(int index);

        //! format to xml
        bool formatToXml(ref XmlElement basicMetaDataEle);

        //! load xml
        bool loadXml(XmlElement basicMetaData);
    };

    //! Basic meta data
    public interface IBasicMeta
    {
        //! Alias Information
        //! get model alias
        string getAlias(int index);

        //! get model alias count
        int AliasCount { get; }

        //! add an alias
        int insertAlias(string alias);

        //! remove an alias
        int removeAlias(int index);

        //! Domain Information
        //! get domain
        string getDomain(int index);

        //! get domains count
        int DomainsCount { get; }

        //! add a domain
        int insertDomain(string domain);

        //! remove a domain
        int removeDomain(int index);

        //! Mechanism Information
        //! get model mechanism item
        MechanismItem getMechanism(int index);

        //! get model mechanism count
        int MechanismCount { get; }

        //! add a mechanism item
        int insertMechanism(MechanismItem item);

        //! remove a mechanism item
        int removeMechanism(int index);

        //! Model Methods
        //! get model method
        MethodItem getMethod(int index);

        //! get model methods count
        int MethodsCount { get; }

        //! add a model method
        int insertMethod(MethodItem item);

        //! remove a model method
        int removeMethod(int index);

        //! get spatiotemporal interface
        ISpatiotemporalInfo getSpatiotemporalInfo();

        //! Contributor Information
        //! get a contributor
        IContributor getContributor(int index);

        //! get contributors count
        int ContributorsCount { get; }

        //! add a contributor
        int insertContributor(Contributor item);

        //! remove a contributor
        int removeContributor(int index);

        //! Components
        //! get a component
        ComponentItem getComponent(int index);

        //! component count
        int ComponentsCount { get; }

        //! add component
        int insertComponent(ComponentItem item);

        //! remove component
        int removeComponent(int index);

        //! Processing
        //! get processing
        ProcessingItem getProcessing(int index);

        //! get processing count
        int ProcessingCount { get; }

        //! add a processing
        int insertProcessing(ProcessingItem item);

        //! remove a processing
        int removeProcessing(int index);

        //! Programming Languages
        //! get programming language
        EProgrammingLanguage getProgrammingLanguage(int index);

        //! get programming languages count
        int ProgrammingLanguagesCount { get; }

        //! add a programming language
        int insertProgrammingLanguage(EProgrammingLanguage language);

        //! remove a programming language
        int removeProgrammingLanguage(int index);

        //! Potential Coupling Component
        //! get coupling component
        PotentialCouplingComponent getCouplingComponent(int index);

        //! get coupling components count
        int CouplingComponentsCount { get; }

        //! add a coupling component
        int insertCouplingComponent(PotentialCouplingComponent item);

        //! remove a coupling component
        int removeCouplingComponent(int index);

        //! format to xml
        bool formatToXml(ref XmlElement modelClassExtentEle);

        //! load xml
        bool loadXml(XmlElement basicMetaData);
    };

    //! Extended meta data node type
    public enum EExtendedType
    {
        EET_Unknown = 0,
        EET_Value = 1,
        EET_Group = 2
    }

    //! Extended meta data
    public interface IExtendedMeta
    {
        //! add a value
        bool addValue(string key, string value);

        //! add a group
        bool addGroup(string key, IExtendedMeta group);

        //! key existing
        bool isKeyExisting(string key);

        //! revome a key
        bool removeKey(string key);

        //! get key type
        EExtendedType getKeyType(string key);

        //! get value
        string getValue(string key);

        //! get group
        IExtendedMeta getGroup(string key);

        //! get all values keys
        List<string> getAllValueKeys();

        //! get all group keys
        List<string> getAllGroupKeys();

        //! get root
        IExtendedMeta Root { get; }

        //! parent
        IExtendedMeta Parent { get; }

        //! format
        bool formatToXml(ref XmlElement extendedmeta, string key = "");

        //! load
        bool loadXml(XmlElement extendedmeta);

        ////!get root group
        //IExtendedMeta RootGroup { get; }

        ////!get parent group
        //IExtendedMeta Parent { get; set; }

        ////! get self key
        //string Key { get; }

        ////! get child type
        //EExtendedType getChildType(string key);

        ////! get child value
        //string getValue(string key);

        ////! get child group
        //IExtendedMeta getGroup(string key);

        ////! get all group
        //Dictionary<string, IExtendedMeta> AllGroup { get; set; }

        ////! get all value
        //Dictionary<string, string> AllValue { get; set; }

        ////! insert a child value
        //int insertValue(string key, string value);

        ////! insert a child node
        //int insertGroup(string key, IExtendedMeta group);

        //int insertGroup(ref ExtendedMeta group);

        ////! remove a child value
        //int removeValue(string key);

        ////! remove a child key
        //int removeChild(string key);

        ////! update a child value
        //int updateValue(string key, string value);

        ////! update a child node
        //int updateGroup(string key, IExtendedMeta group);

        ////! format to Xml
        //bool formatToXml(XmlElement modelClassExtentEle);
    };

    ////! Extended meta value
    //public interface IExtendedMetaValue
    //{
    //    //! get root group
    //    IExtendedMeta RootGroup { get; }

    //    //! ger parent group
    //    IExtendedMeta ParentGroup { get; }

    //    //! get key
    //    string Key { get; }

    //    //! get value
    //    string Value { get; }

    //}

    //! Meta Data Document
    public interface IMetaDataDocument
    {
        //! get basic meta data interface
        IBasicMeta getBasicMetaData();

        //! get extent meta data interface
        IExtendedMeta getExtentMetaData();

        //! format to stream
        string format2Stream();

        //! format to file
        int format2File(string filepath);

        //! load from stream
        int loadStream(string stream);

        //! load from file
        int loadFile(string filepath);
    };
}
